package qq2564874169.tuaotuao.fx.utils;



import qq2564874169.tuaotuao.fx.FxDate;
import qq2564874169.tuaotuao.fx.caching.AppCache;
import qq2564874169.tuaotuao.fx.caching.Cache;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

public class ConvertUtil {
    private static Cache cache = new AppCache();

    public static <T> T change(Object value, Class<T> clazz) {
        if (value == null) {
            if (clazz.isPrimitive() == false) {
                return null;
            }
            value = "0";
        }
        if (clazz.isInstance(value)) {
            return (T) value;
        }
        try {
            if (clazz == String.class) {
                return (T) toStr(value);
            }
            if (clazz == boolean.class || clazz == Boolean.class) {
                return (T) toBool(value);
            }
            if (clazz.isEnum()) {
                return (T) toEnum((Class<? extends Enum>) clazz, value);
            }
            if (clazz == Date.class) {
                return (T) toDate(value);
            }
            if (clazz == char.class || clazz == Character.class) {
                return (T) toChar(value);
            }
            if (clazz == int.class || clazz == Integer.class) {
                return (T) toInt(value);
            }
            String srcNum = value.toString().trim();
            if (Pattern.matches("^-?\\d+(\\.\\d+)?$", srcNum)) {
                if (clazz == BigDecimal.class) {
                    return (T) new BigDecimal(srcNum);
                }
                if (clazz == short.class || clazz == Short.class) {
                    BigDecimal num = new BigDecimal(srcNum);
                    return (T) Short.valueOf(num.shortValue());
                }
                if (clazz == long.class || clazz == Long.class) {
                    BigDecimal num = new BigDecimal(srcNum);
                    return (T) Long.valueOf(num.longValue());
                }
                if (clazz == double.class || clazz == Double.class) {
                    BigDecimal num = new BigDecimal(srcNum);
                    return (T) Double.valueOf(num.doubleValue());
                }
                if (clazz == float.class || clazz == Float.class) {
                    BigDecimal num = new BigDecimal(srcNum);
                    return (T) Float.valueOf(num.floatValue());
                }
                if (clazz == byte.class || clazz == Byte.class) {
                    BigDecimal num = new BigDecimal(srcNum);
                    return (T) Byte.valueOf(num.byteValue());
                }
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    private static Object toStr(Object value) {
        if (value instanceof Enum) {
            return ((Enum) value).name();
        }
        if (value instanceof Date) {
            return new FxDate(((Date) value)).format();
        }
        return value.toString();
    }

    private static Object toEnum(Class<? extends Enum> clazz, Object value) throws Exception {
        Enum[] es = (Enum[]) clazz.getMethod("values").invoke(null);
        Integer num = null;
        if (value instanceof Integer) {
            num = (Integer) value;
        } else if (Pattern.matches("^\\d+$", value.toString())) {
            num = Integer.parseInt(value.toString());
        }
        if (num != null) {
            Enum o = EnumUtil.parseById(clazz, num);
            if (o != null) {
                return o;
            }
            for (Enum item : es) {
                if (num.equals(item.ordinal())) {
                    return item;
                }
            }
            return null;
        }
        for (Enum item : es) {
            if (item.name().equals(value)) {
                return item;
            }
        }
        return null;
    }

    private static Object toInt(Object value) {
        if (value instanceof Enum) {
            Integer id = EnumUtil.getId((Enum) value);
            if (id != null) {
                return id;
            } else {
                return ((Enum) value).ordinal();
            }
        }
        return new BigDecimal(value.toString().trim()).intValue();
    }

    private static Object toDate(Object value) {
        if (value instanceof String) {
            if (Pattern.matches("^\\d{13}$", (String) value)) {
                return new Date(Long.parseLong((String) value));
            }
            if (Pattern.matches("^\\d{8}$", (String) value)) {
                return FxDate.parseByExpr((String) value, "yyyyMMdd");
            }
            String[] ps;
            if (value.toString().contains(" ")) {
                ps = new String[]{"yyyy-MM-dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss.SSS"};
            } else {
                ps = new String[]{"yyyyMMddHHmmss", "yyyy/MM/dd", "yyyy-MM-dd", "yyyy.MM.dd"};
            }
            for (String pat : ps) {
                try {
                    return new SimpleDateFormat(pat).parse(value.toString());
                } catch (ParseException ignored) {

                }
            }
        } else if (value instanceof Long) {
            return new Date((Long) value);
        }
        return null;
    }

    private static Object toChar(Object value) {
        if (value instanceof Character) {
            return value;
        }
        if (value instanceof Integer) {
            return (char) ((Integer) value).intValue();
        }
        if (value instanceof String) {
            char[] items = value.toString().toCharArray();
            return items.length > 0 ? items[0] : null;
        }
        return null;
    }

    private static Object toBool(Object value) {
        String str = value.toString();
        if ("false".equalsIgnoreCase(str) || "0".equals(str)) {
            return Boolean.FALSE;
        }
        if ("true".equalsIgnoreCase(str) || "1".equals(str)) {
            return Boolean.TRUE;
        }
        return null;
    }

//    public static void main(String[] args) throws ParseException {
//        System.out.println(change(-3467, Long.class));
//    }
}
